/*
 * The MiniQt Library
 *
 * Copyright (C) 1999 Sandro Sigala <ssigala@globalnet.it>
 */

#include "qobject.h"
#include "qstring.h"

struct QObjectPrivate {
	const char *name;
	QObject *parent;
	QObjectList childs;

	// Meta object data
	QList<QString> existing_signals;
	struct SignalLink {
		const char *signame;
		const char *slotname;
		QObject *dest;
	};
	QList<SignalLink> signal_links;
	struct SlotLink {
		const char *slotname;
		QObject *dest;
		QMember member;
	};
	QList<SlotLink> slot_links;
};

/*
 * Public
 */

QObject::QObject(QObject *parent, const char *name)
{
#ifdef DEBUG
	qDebug("obj", "QObject::constructor of \"%s\"", name ? name : "unnamed");
#endif
	d = new QObjectPrivate;
	d->parent = parent;
	d->name = name;
	if (d->parent)
		parent->registerChild(this);

	// Meta object
	d->existing_signals.setAutoDelete(TRUE);
	d->signal_links.setAutoDelete(TRUE);
	d->slot_links.setAutoDelete(TRUE);
}

QObject::~QObject()
{
#ifdef DEBUG
	qDebug("obj", "QObject::destructor of \"%s\"", name("unnamed"));
#endif
	if (d->parent)
		d->parent->unregisterChild(this);
	deleteChilds();
	delete d;
}

const char *QObject::name() const
{
	return d->name;
}

const char *QObject::name(char *defname) const
{
	return d->name ? d->name : defname;
}

void QObject::setName(const char *name)
{
	d->name = name;
}

QObject *QObject::parent() const
{
	return d->parent;
}

const QObjectList *QObject::children()
{
	return &d->childs;
}

bool QObject::isWidgetType() const
{
	return FALSE;
}

const char *QObject::className() const
{
	return "QObject";
}

void QObject::connect(QObject *src, const char *signame, QObject *dest, const char *slotname)
{
	src->initMetaObject();
	dest->initMetaObject();
	src->addConnection(signame, dest, slotname);
}

/*
 * Protected
 */

void QObject::initMetaObject()
{
	qWarning("QObject::initMetaObject(): called base function instead of moc function");
}

void QObject::registerSignal(const char *signame)
{
	qDebug("moc", "registering signal %s into \"%s\"", signame, name("unnamed"));
	d->existing_signals.append(new QString(signame));
}

void QObject::calledSignal(const char *signame)
{
#ifdef DEBUG
	qDebug("moc", "called signal %s of \"%s\"", signame, name("unnamed"));
#endif
	bool found = FALSE;
	for (QString *sp = d->existing_signals.first(); sp != 0; sp = d->existing_signals.next())
		if (*sp == signame) {
			found = TRUE;
			break;
		}
	if (!found) {
		qWarning("QObject::calledSignal(): no such signal %s", signame);
		return;
	}

	for (QObjectPrivate::SignalLink *l = d->signal_links.first(); l != 0; l = d->signal_links.next())
		if (!strcmp(l->signame, signame)) {
			l->dest->calledSlot(l->slotname);
		}
}

void QObject::registerSlot(const char *slotname, QObject *dest, QMember member)
{
	qDebug("moc", "registering slot %s into \"%s\"", slotname, name("unnamed"));
	QObjectPrivate::SlotLink *l = new QObjectPrivate::SlotLink;
	l->slotname = slotname;
	l->dest = dest;
	l->member = member;
	d->slot_links.append(l);
}

void QObject::calledSlot(const char *slotname)
{
#ifdef DEBUG
	qDebug("moc", "calling slot %s of \"%s\"", slotname, name("unnamed"));
#endif
	for (QObjectPrivate::SlotLink *l = d->slot_links.first(); l != 0; l = d->slot_links.next())
		if (!strcmp(l->slotname, slotname)) {
			QObject *o = l->dest;
			QMember member = l->member;
			(o->*member)();
			return;
		}

	qWarning("QObject::calledSlot(): no such slot %s", slotname);
}

/*
 * Private
 */

void QObject::registerChild(QObject *child)
{
#ifdef DEBUG
	qDebug("child", "registering child \"%s\" into \"%s\"", child->name("unnamed"), name("unnamed"));
#endif
	d->childs.append(child);
}

void QObject::unregisterChild(QObject *child)
{
#ifdef DEBUG
	qDebug("child", "unregistering child \"%s\" from \"%s\"", child->name("unnamed"), name("unnamed"));
#endif
	d->childs.take(child);
}

void QObject::deleteChilds()
{
	for (QObject *o = d->childs.first(); o != 0; o = d->childs.current()) {
#ifdef DEBUG
		qDebug("child", "deleting child \"%s\" from \"%s\"", o->name("unnamed"), name("unnamed"));
#endif
		d->childs.remove(o);
		delete o;
	}
}

void QObject::addConnection(const char *signame, QObject *dest, const char *slotname)
{
	qDebug("moc", "connecting signal %s of \"%s\" to slot %s of \"%s\"",
	       signame, name("unnamed"), slotname, dest->name("unnamed"));
	QObjectPrivate::SignalLink *l = new QObjectPrivate::SignalLink;
	l->signame = signame;
	l->slotname = slotname;
	l->dest = dest;
	d->signal_links.append(l);
}
